Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Make name lookups in api endpoints case insensitive #1190

Merged
merged 1 commit into from
Jan 21, 2025

Conversation

FallenDeity
Copy link
Contributor

@FallenDeity FallenDeity commented Jan 21, 2025

Solves issue #1179 makes lookup via name case-insensitive, for example

In [1]: import requests as r

In [2]: x = r.get('http://localhost:8000/api/v2/pokemon/Bulbasaur/')

In [3]: y = r.get('http://localhost:8000/api/v2/pokemon/bulbasaur/')

In [4]: x.status_code, y.status_code
Out[4]: (200, 200)

In [5]: x.json()["name"], y.json()["name"]
Out[5]: ('bulbasaur', 'bulbasaur')

Minor changes in lookup logic now uses [__iexact](https://docs.djangoproject.com/en/dev/ref/models/querysets/#iexact) for querying.

Test cases are added for case-insensitive testing for the api:

pokeapi/pokemon_v2/tests.py

Lines 5695 to 5799 in 63f0e26

def test_case_insensitive_api(self):
# Set up pokemon data
pokemon_species = self.setup_pokemon_species_data(
name="pkmn spcs for base pkmn"
)
pokemon = self.setup_pokemon_data(
pokemon_species=pokemon_species, name="base pkm"
)
pokemon_form = self.setup_pokemon_form_data(
pokemon=pokemon, name="pkm form for base pkmn"
)
generation = self.setup_generation_data(name="base gen")
pokemon_ability = self.setup_pokemon_ability_data(pokemon=pokemon)
pokemon_past_ability = self.setup_pokemon_past_ability_data(
pokemon=pokemon, generation=generation
)
pokemon_stat = self.setup_pokemon_stat_data(pokemon=pokemon)
pokemon_type = self.setup_pokemon_type_data(pokemon=pokemon)
pokemon_past_type = self.setup_pokemon_past_type_data(
pokemon=pokemon, generation=generation
)
pokemon_item = self.setup_pokemon_item_data(pokemon=pokemon)
pokemon_sprites = self.setup_pokemon_sprites_data(pokemon=pokemon)
pokemon_cries = self.setup_pokemon_cries_data(pokemon, latest=True, legacy=True)
pokemon_game_index = self.setup_pokemon_game_index_data(
pokemon=pokemon, game_index=10
)
# To test issue #85, we will create one move that has multiple
# learn levels in different version groups. Later, we'll
# assert that we only got one move record back.
pokemon_move = self.setup_move_data(name="mv for pkmn")
pokemon_moves = []
for move in range(0, 4):
version_group = self.setup_version_group_data(
name="ver grp " + str(move) + " for pkmn"
)
new_move = self.setup_pokemon_move_data(
pokemon=pokemon,
move=pokemon_move,
version_group=version_group,
level=move,
)
pokemon_moves.append(new_move)
encounter_method = self.setup_encounter_method_data(
name="encntr mthd for lctn area"
)
location_area1 = self.setup_location_area_data(name="lctn1 area for base pkmn")
encounter_slot1 = self.setup_encounter_slot_data(
encounter_method, slot=1, rarity=30
)
self.setup_encounter_data(
location_area=location_area1,
pokemon=pokemon,
encounter_slot=encounter_slot1,
min_level=30,
max_level=35,
)
location_area2 = self.setup_location_area_data(name="lctn2 area for base pkmn")
encounter_slot2 = self.setup_encounter_slot_data(
encounter_method, slot=2, rarity=40
)
self.setup_encounter_data(
location_area=location_area2,
pokemon=pokemon,
encounter_slot=encounter_slot2,
min_level=32,
max_level=36,
)
lowercase_name = pokemon.name.lower()
uppercase_name = pokemon.name.upper()
# Test lowercase
lowercase_response = self.client.get(
"{}/pokemon/{}/".format(API_V2, lowercase_name), HTTP_HOST="testserver"
)
self.assertEqual(lowercase_response.status_code, status.HTTP_200_OK)
# Test uppercase
uppercase_response = self.client.get(
"{}/pokemon/{}/".format(API_V2, uppercase_name), HTTP_HOST="testserver"
)
self.assertEqual(uppercase_response.status_code, status.HTTP_200_OK)
self.assertEqual(lowercase_response.data, uppercase_response.data)
# Same test with /language endpoint
language = self.setup_language_data(name="base-lang")
language_name = self.setup_language_name_data(language, name="base-lang-name")
lowercase_name = language.name.lower()
uppercase_name = language.name.upper()
lowercase_response = self.client.get(
"{}/language/{}/".format(API_V2, lowercase_name), HTTP_HOST="testserver"
)
self.assertEqual(lowercase_response.status_code, status.HTTP_200_OK)
uppercase_response = self.client.get(
"{}/language/{}/".format(API_V2, uppercase_name), HTTP_HOST="testserver"
)
self.assertEqual(uppercase_response.status_code, status.HTTP_200_OK)
self.assertEqual(lowercase_response.data, uppercase_response.data)

@Naramsim feel free to take a look when you have some time

@phalt
Copy link
Member

phalt commented Jan 21, 2025

This is a cool implementation but it is worth noting that this won't be inherited by the live pokeapi.co instance - the way we build and deploy that generates thousands of static files that we upload, and there is no live server to do the case insensitive look up.

An alternative would be to use Ditto (the tool we use) to crawl each endpoint with all possible case inputs, but that would generate a gigantic number of files and might not be applicable.

We could also update the small app function we use to lower case the input?

@FallenDeity
Copy link
Contributor Author

That works too 🙂, just lower casing the query params should do the trick, afaik all our resource names are also lower case so we should be fine

@Naramsim
Copy link
Member

Yes, if we want the change in the live api, we should change the logic here:

https://github.com/PokeAPI/deploy/blob/master/functions_v1/src/index.js

@Naramsim Naramsim merged commit 9923154 into PokeAPI:master Jan 21, 2025
4 checks passed
@pokeapi-machine-user
Copy link

A PokeAPI/api-data refresh has started. In ~45 minutes the staging branch of PokeAPI/api-data will be pushed with the new generated data.

The staging branch will be deployed in our staging environment and the entire API will be ready to review.

A Pull Request (master<-staging) will be also created at PokeAPI/api-data and assigned to the PokeAPI Core team to be reviewed. If approved and merged new data will soon be available worldwide at pokeapi.co.

@FallenDeity
Copy link
Contributor Author

I'll take a look at the repo and make a pr by hopefully tomorrow 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants